package cn.ztydata.teachingsystem.heaven.web.controller;

import cn.ztydata.teachingsystem.common.Page;
import cn.ztydata.teachingsystem.exception.UploadException;
import cn.ztydata.teachingsystem.heaven.cons.MsgTemplate;
import cn.ztydata.teachingsystem.heaven.entity.Resource;
import cn.ztydata.teachingsystem.heaven.entity.User;
import cn.ztydata.teachingsystem.heaven.entity.exercise.Exercise;
import cn.ztydata.teachingsystem.heaven.service.ExerciseService;
import cn.ztydata.teachingsystem.heaven.service.TestService;
import cn.ztydata.teachingsystem.heaven.util.UploadUtil;
import cn.ztydata.teachingsystem.heaven.web.dto.ResourceListDto;
import cn.ztydata.teachingsystem.heaven.web.dto.exercise.ExerciseDetailDto;
import cn.ztydata.teachingsystem.heaven.web.dto.test.ExerciseForAnswerDto;
import cn.ztydata.teachingsystem.heaven.web.wrapper.HttpSessionProxy;
import cn.ztydata.teachingsystem.util.StringCodeUtil;
import cn.ztydata.teachingsystem.webservice.result.json.JsonResult;
import cn.ztydata.teachingsystem.webservice.result.json.JsonResultData;
import cn.ztydata.teachingsystem.webservice.result.json.JsonResultList;
import cn.ztydata.teachingsystem.webservice.result.json.JsonResultPage;
import com.google.common.collect.Lists;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;


/**
 * 习题库控制器类
 *
 * @author lyj
 * @since 2015-2-4
 */
@Controller
@RequestMapping("/praxis")
public class ExerciseController extends BaseController{
    @Autowired
    private ExerciseService exerciseService;
    @Autowired
    private TestService testService;

    @Value("${file.dir}")
    private String uploadDir;

    @Value("${session.key}")
    private String sessionKey;

    /**
     * 新增习题
     * @param exerciseDto 习题对象dto
     * @return JsonResult 是否成功
     *
     * @author wyh
     * @since 2015-2-5
     */
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @ResponseBody
    public JsonResult saveExercise(@RequestBody @Valid ExerciseDetailDto exerciseDto) {
        //校验Dto
        Assert.notNull(exerciseDto, "发送的信息错误");

        //校验分数、难度、专业ID、公开
        Assert.notNull(exerciseDto.getScore(), "习题分值不可为空");
        Assert.notNull(exerciseDto.getDifficulty(), "习题难度不可为空");
        Assert.notNull(exerciseDto.getMajorId(), "专业ID不可为空");
        Assert.notNull(exerciseDto.getIsOpen(), "是否公开不可为空");

        //转换实体
        Exercise exercise = mapper.map(exerciseDto, Exercise.class);

        List<Long> exerciseIds = exerciseService.saveExercise(exercise);

        if(!exerciseIds.isEmpty()){
            //附件转换、生成附件显示地址
            for(Long id : exerciseIds) {
                exerciseService.transformAttachment(id, exercise.getDownloadAddress());
            }
        }

        log.debug("新增习题成功");
        return new JsonResult(true, "新增习题成功");
    }

    /**
     * 统计不同类型习题的总数
     *
     * @author chenxin
     * @since 2015/2/4
     */
    @RequestMapping(value = "/statistics", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getStatistics() {
        //获取不同习题类型的习题总数
        Map<String, Object> result = exerciseService.getStatistics();

        log.debug("返回统计结果");
        return new JsonResultData(result);
    }


    /**
     * 审核/删除习题
     * @param mapAudit
     * @return
     * @author lyj
     * @since 2015-2-4
     */
    @RequestMapping(value = "/audit", method = RequestMethod.PUT)
    @ResponseBody

    public JsonResult auditExercise(@RequestBody Map<String, Object> mapAudit){

        Assert.isTrue(Long.parseLong(mapAudit.get("id").toString()) > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "习题ID"));
        Assert.isTrue((int)mapAudit.get("status") >= 0 && (int)mapAudit.get("status") < 4, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "状态ID"));
        Assert.isTrue(Long.parseLong(mapAudit.get("majorId").toString()) > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "专业ID"));
        Assert.isTrue((int)mapAudit.get("tag") >= 0 && (int)mapAudit.get("tag") < 3,  MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "tag标记"));

        exerciseService.auditExercise(mapAudit);

        log.debug("审核、删除成功");
        return new JsonResult(true,"操作成功");


    }

    /**
     * 统计专业习题数
     * @param deptCode 系部编码
     * @return JsonResultList<Map<String,Object>> 专业列表
     * @author lyj
     * @since 2015-2-5
     */
    @RequestMapping(value = "/majorList/{deptCode}/{tag}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultList<Map<String, Object>> getSpecExercises(@PathVariable String deptCode,
                                                                @PathVariable int tag,
                                                                @RequestParam(value = "search", required = false) String search){
        Assert.hasText(deptCode.trim(), MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "系部编码"));
        Assert.isTrue(tag >= 0 && tag <= 3, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "专业统计方法里的tag标记") );

        search = StringCodeUtil.urlParamTransCode(search, "utf-8"); //汉字转码
        search = StringEscapeUtils.escapeHtml4(search); //转换符号

        log.debug("统计专业习题数");
        return new JsonResultList<>(exerciseService.getSpecExercises(deptCode, tag, search));
    }

    /**
     * 统计系部习题数
     *
     * @return
     * @author lyj
     * @since 2015-2-5
     */
    @RequestMapping(value = "/deptList/{tag}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultList<Map<String, Object>> getDepartExercises(@PathVariable int tag,
                                                                  @RequestParam(value = "search", required = false) String search){
        Assert.isTrue(tag >= 0 && tag <= 3, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "系部统计方法里的tag标记"));

        search = StringCodeUtil.urlParamTransCode(search, "utf-8"); //汉字转码
        search = StringEscapeUtils.escapeHtml4(search); //转换符号

        log.debug("获取系部习题数");
        return new JsonResultList<>(exerciseService.getDepartExercises(tag, search));
    }


    /**
     * 习题引用解析
     *
     * @return
     * @author lyj
     * @since 2015-2-5
     */
    @RequestMapping(value = "/resource/{exerciseId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultList getResAnalysis(@PathVariable long exerciseId){

        Assert.isTrue(exerciseId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"习题ID"));

        List<Resource> resources = exerciseService.getResAnalysis(exerciseId);

        log.debug("习题引用解析");
        return new JsonResultList<>(mapper.mapList(resources, ResourceListDto.class));
    }


    /**
     * 习题列表
     * @param pageNum 当前页码
     * @param pageSize 每页条数
     * @param deptId 系部ID
     * @param specId 专业ID
     * @param tag 标记
     * @param status 习题状态
     * @param isOpen 是否公开
     * @param search 关键字
     * @param type 习题类型
     * @return JsonResultList
     * @author lyj
     * @since 2015-2-6
     */
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultPage getExerciseList(@RequestParam("page") int pageNum,
                                          @RequestParam("pageSize") int pageSize,
                                          @RequestParam("deptId") long deptId,
                                          @RequestParam("majorId") long specId,
                                          @RequestParam("tag") int tag,
                                          @RequestParam("status") int status,
                                          @RequestParam("isOpen") int isOpen,
                                          @RequestParam(value = "search", required = false) String search,
                                          @RequestParam("type") List<Long> type){
        //数据验证
        Assert.isTrue(pageNum > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"当前页码"));
        Assert.isTrue(pageSize > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"每页条数"));
        Assert.isTrue(deptId >= 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"系部ID"));//待审核列表，系部、专业联动禁用
        Assert.isTrue(specId >= 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"专业ID"));//待审核列表，系部、专业联动禁用
        Assert.isTrue(tag >= 0 && tag <= 3, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"tag标记"));
        Assert.isTrue(status >= 0 && status <= 4, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"习题状态"));
        Assert.isTrue(isOpen >= 0 && isOpen <= 2, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"私有公开标记"));

        Assert.isTrue(type != null && type.size() > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"习题类型"));

        search = StringCodeUtil.urlParamTransCode(search, "utf-8"); //汉字转码
        search = StringEscapeUtils.escapeHtml4(search); //转换符号

        Page<Exercise> exercisePage = exerciseService.getExerciseList(pageNum, pageSize, deptId, specId, tag, status, isOpen, search, type);

        log.debug("习题列表");
        //向前台转换
        return new JsonResultPage(new Page(exercisePage.getTotal(), pageSize, pageNum, mapper.mapList(exercisePage.getItems(), ExerciseDetailDto.class)));

    }

    /**
     * 获取习题列表明细
     * @param exerciseId 习题ID
     * @return
     * @author lyj
     * @since 2015-2-9
     */
    @RequestMapping(value = "/detail/{exerciseId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultData getExerDetail(@PathVariable long exerciseId) {
        //数据验证
        Assert.isTrue(exerciseId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "习题ID"));

        Exercise exercise = exerciseService.getExerDetail(exerciseId);

        log.debug("获取习题列表明细");
        return new JsonResultData<>(mapper.map(exercise, ExerciseDetailDto.class));

    }

    /**
     * 上传习题附件
     * @param attachmentFile 附件文件
     * @return JsonResultData
     *
     * @author wyh
     * @since 2015-2-11
     */
    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    @ResponseBody
    public JsonResultData uploadAttachment(@RequestParam("data") MultipartFile attachmentFile){
        //定义允许上传的附件类型
        List fileTypes = Lists.newArrayList("doc", "docx", "mp3", "wma", "mp4", "flv", "swf", "gif", "jpg", "jpeg", "bmp", "png"
        ,"txt", "ppt", "pptx", "xls", "xlsx", "rtf", "pdf", "rar", "zip","htm", "html", "xml");
        String url = null;

        try{
            //校验上传的文件
            UploadUtil.validateFile(attachmentFile, fileTypes);

            //保存上传的文件
            String fileExt = UploadUtil.getFileExt(attachmentFile.getOriginalFilename());

            //生成文件上传的地址
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            url = "/"+sdf.format(new Date()) + "/" + UploadUtil.generateFileName(fileExt);

            //上传文件流
            File file = new File(uploadDir, url);
            FileUtils.writeByteArrayToFile(file, attachmentFile.getBytes());

            log.debug("上传附件成功");

            return new JsonResultData(url, "上传附件成功");
        }catch (IOException ex){
            log.debug("上传附件时IO异常");

            return new JsonResultData(false, "上传失败");
        }catch (UploadException ex){
            log.debug("附件校验失败");

            return new JsonResultData(false, ex.getMessage());
        }
    }


    /**
     * 根据习题ID获取附件预览信息
     * @param exerciseId  习题ID
     * @return
     * @author lyj
     * @since 2015-3-9
     */
    @RequestMapping(value = "/attachmentDetail/{exerciseId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResultData getShowAnnex(@PathVariable long exerciseId){
        //数据验证
        Assert.isTrue(exerciseId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "习题ID"));

        return new JsonResultData(exerciseService.getShowAnnex(exerciseId));
    }

    /**
     * 习题附件转换
     * @param exerciseId  习题ID
     * @param downloadUrl 附件下载地址
     * @return
     * @author lyj
     * @since 2015-3-9
     */
    @RequestMapping(value = "/attachmentCoverter/{exerciseId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult transformAttachment(@PathVariable long exerciseId,
                                          @RequestParam("downloadUrl") String downloadUrl){
        //数据验证
        Assert.isTrue(exerciseId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "习题ID"));
        Assert.hasText(downloadUrl, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "附件地址"));
        Assert.notNull(downloadUrl, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "附件地址"));

        exerciseService.transformAttachment(exerciseId, downloadUrl);

        return new JsonResult(true, "文件正在转换，请刷新查看");
    }

    /**
     * 线上作业待选习题列表
     * @param majorId 专业编号
     * @param source 来源（0：系统题库，1：我的题库）
     * @param type 类型（0：全部，1：单选，2：多选，3：判断，4：填空，5：简答，6：阅读，7：阅读多问）
     * @param pageNum 页码
     * @param pageSize 每页显示条数
     * @param knowledge
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-03-27
     */
    @ResponseBody
    @RequestMapping(value = "/testList/{majorId}/{source}/{type}/{pageNum}/{pageSize}", method = RequestMethod.GET)
    public JsonResult listForTest(@PathVariable Long majorId,@PathVariable int source,@PathVariable int type,@PathVariable int pageNum
    ,@PathVariable int pageSize,@RequestParam(value = "knowledge", required = false) String knowledge,HttpServletRequest request){
        //数据验证
        Assert.isTrue(pageNum > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"当前页码"));
        Assert.isTrue(pageSize > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"每页条数"));
        Assert.isTrue(majorId >= 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"专业编号"));
        Assert.isTrue(source == 0 || source == 1, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"来源"));
        Assert.isTrue(type >= 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"习题类型"));

        HttpSessionProxy httpSessionProxy = (HttpSessionProxy)request.getSession();

        //获取当前用户信息
        User entity = (User)httpSessionProxy.getAttribute(sessionKey);

        //获取习题列表分页数据
        Page<Exercise> page = exerciseService.getListForTest(entity.getUserId(), knowledge, majorId, source, type, pageNum, pageSize);

        //Entity转换Dto
        Page<ExerciseDetailDto> detailDtoPage = new Page<>(page.getTotal(),pageSize,pageNum,mapper.mapList(page.getItems(),ExerciseDetailDto.class));

        return new JsonResultPage<>(detailDtoPage);
    }

    /**
     * 习题明细
     * @param id 习题编号
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-03-31
     */
    @ResponseBody
    @RequestMapping(value = "/standbyDetail/{id}", method = RequestMethod.GET)
    public JsonResult standbyDetail(@PathVariable Long id){
        //数据验证
        Assert.isTrue(id > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "习题编号"));

        Exercise exercise = exerciseService.getDetail(id);

        return new JsonResultData<>(mapper.map(exercise, ExerciseDetailDto.class));
    }

    /**
     * 学生答题复习明细
     *
     * @param testId 作业ID
     * @param exerciseId 习题ID
     * @param studentId 学生ID
     * @return json
     * 
     * @author cx
     * @since 2015/4/3
     */
    @RequestMapping(value = "/studentAnswerDetail/{studentId}/{exerciseId}/{testId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getDetailOfAnswer(@PathVariable long testId, @PathVariable long exerciseId, @PathVariable long studentId) {
        //校验参数
        Assert.isTrue(testId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "作业测试ID"));
        Assert.isTrue(exerciseId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "习题ID"));
        Assert.isTrue(studentId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "学生ID"));

        //获取学生作业答题明细
        Exercise exercise = testService.getTEForReview(studentId, testId, exerciseId);

        log.debug("学生答题复习明细");
        //转为dto
        return new JsonResultData<>(mapper.map(exercise, ExerciseForAnswerDto.class));
    }

    /**
     * 获取系部下当前用户创建的习题资源数量
     * @param search 查询关键字
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-05-06
     */
    @RequestMapping(value = "/myDepartStatistics", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult myDepartStatistics(@RequestParam String search){
        //搜索关键字转码
        search = StringCodeUtil.urlParamTransCode(search, "utf-8");

        List<Map<String,Object>> exerciseTotal = exerciseService.getTotalForDepartment(search);

        return new JsonResultList<>(exerciseTotal);
    }

    /**
     * 获取专业下当前用户创建的习题资源数量
     * @param search 查询关键字
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-05-06
     */
    @RequestMapping(value = "/myMajorStatistics", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult myMajorStatistics(@RequestParam String search,@RequestParam String departCode){
        //搜索关键字转码
        search = StringCodeUtil.urlParamTransCode(search, "utf-8");

        List<Map<String,Object>> exerciseTotal = exerciseService.getTotalForSpecialty(search, departCode);

        return new JsonResultList<>(exerciseTotal);
    }

    /**
     * 我创建的习题列表
     * @param departId 系部编号(0：全部)
     * @param majorId 专业编号(0：全部)
     * @param search 搜索关键字
     * @param types 题型
     * @param page 页码
     * @param pageSize 分页
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-05-06
     */
    @RequestMapping(value = "/myList", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult myList(@RequestParam Long departId,@RequestParam Long majorId,@RequestParam String search,
                             @RequestParam(value = "type") List<Integer> types, @RequestParam int page, @RequestParam int pageSize){
        //数据验证
        Assert.isTrue(page > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"当前页码"));
        Assert.isTrue(pageSize > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"每页条数"));
        Assert.isTrue(majorId >= 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"专业编号"));
        Assert.isTrue(departId >= 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR,"系部编号"));

        //搜索关键字转码
        search = StringCodeUtil.urlParamTransCode(search, "utf-8");

        Page<Exercise> exercisePage = exerciseService.getListForMine(departId,majorId,types,search,page,pageSize);

        Page<ExerciseDetailDto> exerciseDetailDtoPage = new Page<>(exercisePage.getTotal(),pageSize,page,mapper.mapList(exercisePage.getItems(),ExerciseDetailDto.class));

        return new JsonResultPage<>(exerciseDetailDtoPage);
    }
}
